package me.aartikov.alligator;


import me.aartikov.alligator.destinations.AbilityDestination;
import me.aartikov.alligator.destinations.Destination;
import me.aartikov.alligator.destinations.DialogFragmentDestination;
import me.aartikov.alligator.destinations.FragmentDestination;
import me.aartikov.alligator.navigationfactories.NavigationFactory;
import me.aartikov.alligator.helpers.DialogFraction;
import me.aartikov.alligator.helpers.MiFraction;
import me.aartikov.alligator.util.Log;
import ohos.aafwk.ability.Ability;

/**
 * Helps to get screens from activities and fragments.
 */
public class ScreenResolver {
    private NavigationFactory mNavigationFactory;

    public ScreenResolver(NavigationFactory navigationFactory) {
        mNavigationFactory = navigationFactory;
    }

    /**
     * Gets a screen from an activity.
     *
     * @param <ScreenT> screen type
     * @param activity  activity containing a screen data in its intent
     * @return a screen gotten from the activity intent
     * @throws IllegalArgumentException if screen getting failed
     */
    @SuppressWarnings("unchecked")

    public <ScreenT extends me.aartikov.alligator.Screen> ScreenT getScreen(Ability activity) {
        ScreenT screen = (ScreenT) getDestination(activity).getScreen(activity);
        if (screen != null) {
            return screen;
        } else {
            throw new IllegalArgumentException("IntentConverter returns null for " + activity.getClass().getCanonicalName());
        }
    }

    /**
     * Gets a screen from an activity (nullable version). Note: it still can throw exceptions in some cases.
     *
     * @param <ScreenT> screen type
     * @param activity  activity
     * @return a screen gotten from the activity intent or null if there are no screen data in the activity.
     * @throws IllegalArgumentException if there are no screens registered for this activity.
     */
    @SuppressWarnings("unchecked")

    public <ScreenT extends me.aartikov.alligator.Screen> ScreenT getScreenOrNull(Ability activity) {
        return (ScreenT) getDestination(activity).getScreen(activity);
    }

    /**
     * Gets a screen from a fragment.
     *
     * @param <ScreenT> screen type
     * @param fragment  fragment containing a screen data in its arguments
     * @return a screen gotten from the fragment
     * @throws IllegalArgumentException if screen getting failed
     */
    @SuppressWarnings("unchecked")

    public <ScreenT extends me.aartikov.alligator.Screen> ScreenT getScreen(MiFraction fragment) {
        return (ScreenT) getDestination(fragment).getScreen(fragment);
    }

    /**
     * Gets a screen from a dialog fragment.
     *
     * @param <ScreenT>      screen type
     * @param dialogFragment dialog fragment containing a screen data in its arguments
     * @return a screen gotten from the dialog fragment
     * @throws IllegalArgumentException if screen getting failed
     */
    @SuppressWarnings("unchecked")

    public <ScreenT extends me.aartikov.alligator.Screen> ScreenT getScreen(DialogFraction dialogFragment) {
        return (ScreenT) getDestination(dialogFragment).getScreen(dialogFragment);
    }


    private AbilityDestination getDestination(Ability activity) {
        Log.i("ScreenResolver.getDestination([activity]):87    "+activity);
        Class<? extends me.aartikov.alligator.Screen> screenClass = mNavigationFactory.getScreenClass(activity);
        if (screenClass == null) {
            throw new IllegalArgumentException("Failed to get screen class from " + activity.getClass().getSimpleName());
        }

        Destination destination = mNavigationFactory.getDestination(screenClass);
        if (!(destination instanceof AbilityDestination)) {
            throw new IllegalArgumentException("Failed to get destination from " + activity.getClass().getSimpleName());
        }

        return (AbilityDestination) destination;
    }


    private FragmentDestination getDestination(MiFraction fragment) {
        Class<? extends me.aartikov.alligator.Screen> screenClass = mNavigationFactory.getScreenClass(fragment);
        if (screenClass == null) {
            throw new IllegalArgumentException("Failed to get screen class from " + fragment.getClass().getSimpleName());
        }

        Destination destination = mNavigationFactory.getDestination(screenClass);
        if (!(destination instanceof FragmentDestination)) {
            throw new IllegalArgumentException("Failed to get destination from " + fragment.getClass().getSimpleName());
        }

        return (FragmentDestination) destination;
    }


    private DialogFragmentDestination getDestination(DialogFraction dialogFragment) {
        Class<? extends Screen> screenClass = mNavigationFactory.getScreenClass(dialogFragment);
        if (screenClass == null) {
            throw new IllegalArgumentException("Failed to get screen class from " + dialogFragment.getClass().getSimpleName());
        }

        Destination destination = mNavigationFactory.getDestination(screenClass);
        if (!(destination instanceof DialogFragmentDestination)) {
            throw new IllegalArgumentException("Failed to get destination from " + dialogFragment.getClass().getSimpleName());
        }

        return (DialogFragmentDestination) destination;
    }
}